Separation Criteria for sSFR vs \(M_\star\)
This code contains an example of the fitting and visualization tools used in the Master Thesis: “Characterization of nuclear activity for galaxies in different large-scale environments in terms of morphology, colour, and specific star formation rate” by Daniel Ariza Quintana.
[1]:
import imageio
import numpy as np
import pandas as pd
import plotly.graph_objects as go
from SliceFit import *
from glob import glob
Data
[2]:
## SUPER TABLA ##
T = pd.read_csv('../Data/Supertabla/Supertabla_A.csv', dtype={'objID':str}) # Todas las galaxias
# Data with conditions
c = (T.logSFR>-10)&(T['logM*']>-10)&(T.Z < 0.1077) # Setting cut in Z for SDSS bias
M = T[c]['logM*'].to_numpy() # Mass
SF = T[c]['log(sSFR)'].to_numpy() # Specific Star Forming Rate
Example
Here we show an example of how the Slice Fit works, and how to use it. It is done for the sSFR vs stellar mass diagram on a logarithmic scale. We make use of the bimodality in the diagram to perform the linear fit separating galaxy populations.
[11]:
# Interactive display of the binodality of the diagram with Plotly
X, Y, Z = contour_params_array(M, SF, Nbins=50)
# Create surface plot
fig = go.Figure(
data=[go.Surface(z=Z, x=X, y=Y, colorscale='Viridis', cmin=10, cmax=1400,
colorbar=dict(len=0.8, thickness=15, yanchor="middle"))],
layout={'height':700, 'width':600}
)
# Customize layout
fig.update_layout(title=r'Bimodality of the sSFR vs stellar mass diagram',
title_font=dict(size=24),
scene=dict(zaxis_title='Counts', xaxis_title=r'log (M*/Ms)',
yaxis_title='log(sSFR/yr-1)')
)
# Show plot
fig.show()
[4]:
# Obtaining the fits for the sSFR vs stellar mass diagram
Nb = 50
Fits = Contour_Fit_sig(M, SF)
/Users/daniarizaq/Desktop/FisyMat/TFM/code/Example/SliceFit.py:103: RuntimeWarning:
Number of calls to function has reached maxfev = 1400.
[5]:
# Plotting the fit
plot_Contour_Fit(M, SF, Fits, 'Example', cmin=10, nc=15, hw=0.11)
50it [00:06, 7.65it/s]
[6]:
# To visualize we make a gif
im_names = glob('./Example/*') # Image names
im_names.sort() # Sort images
gims = []
for n in im_names:
gims.append(imageio.imread(n)) # Load imgs
imageio.mimsave('./SliceFit.gif', gims, 'GIF', fps=5, loop=20) # Create gif
/var/folders/ct/pvdxd6m17rz14sps5rwm3vtw0000gn/T/ipykernel_4904/1925795393.py:6: DeprecationWarning:
Starting with ImageIO v3 the behavior of this function will switch to that of iio.v3.imread. To keep the current behavior (and make this warning disappear) use `import imageio.v2 as imageio` or call `imageio.v2.imread` directly.

Now that we have a double gaussian for every slice we are able to find the minimums.
[7]:
## Finding the minimums between pekas
val = Valley(Fits, M, SF, -14, -8)
We can see there are many points out of the bimodal zone, so we must constrain the valley points before the linear regresion.
[8]:
# Constraining the minimums and fitting.
def f(x,a,b):
return a*x+b
x = val[25:43,0]
y = val[25:43,1]
line, corr = curve_fit(f, x, y)
a, b = line
line = np.array(line)
print(f'a = {a:.4f} +- {corr[0][0]:.4f}')
print(f'b = {b:.4f} +- {corr[1][1]:.4f}')
r = np.linspace(np.min(x), np.max(x))
plt.plot(r, a*r+b, label=f'{a:.3f}x + {b:.3f}')
plt.scatter(x,y)
plt.legend()
a = -0.6961 +- 0.0007
b = -3.8316 +- 0.0851
[8]:
<matplotlib.legend.Legend at 0x16b0d2a90>
[9]:
plot_cont(M,SF,nc=10, scat=val[25:40], linear=line, err=3*corr[1][1])
We arrive to the final fit, which serves as separation criteria for properties, in this case SFR.